package com.znsd.r_e_m.service.imp;

import com.rabbitmq.client.Channel;
import com.znsd.r_e_m.bean.Student;
import com.znsd.r_e_m.dao.StudentMapper;
import com.znsd.r_e_m.service.StudentService;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

@Component
public class StudentServiceImp implements StudentService {

    @Autowired
    StudentMapper studentMapper;

    @RabbitListener(bindings ={
            @QueueBinding(
                    value = @Queue(value = "stuSave",autoDelete = "false"),
                    key={"save"},
                    exchange = @Exchange(type = "topic",name="stuEx")
            )})
    public void save(Student student , Channel channel, Message message, @Headers Map<String, Object> map) throws IOException {
        if (map.get("error") != null) {
            try {
                channel.basicNack((Long) map.get(AmqpHeaders.DELIVERY_TAG), false, true); // 否认消息
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        channel.basicQos(1);
        System.out.println("saveStudent consumer = " + student);
        int result = studentMapper.saveStuden(student);

        //手动ACK
        //默认情况下如果一个消息被消费者所正确接收则会被从队列中移除
        //如果一个队列没被任何消费者订阅，那么这个队列中的消息会被 Cache（缓存），
        //当有消费者订阅时则会立即发送，当消息被消费者正确接收时，就会被从队列中移除
        try {
            //手动ack应答
            //告诉服务器收到这条消息 已经被我消费了 可以在队列删掉 这样以后就不会再发了
            // 否则消息服务器以为这条消息没处理掉 后续还会在发，true确认所有消费者获得的消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
            //丢弃这条消息
            try {
                //最后一个参数是：是否重回队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
                //拒绝消息
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
                //消息被丢失
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                //消息被重新发送
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
                //多条消息被重新发送
                //channel.basicNack(message.getMessageProperties().getDeliveryTag(), true, true);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }


    @RabbitListener(bindings ={
            @QueueBinding(
                    value = @Queue(value = "stuRemove",autoDelete = "false"),
                    key={"remove"},
                    exchange = @Exchange(type = "topic",name="stuEx")
            )})
    public void remove(String ids,Channel channel,Message message,@Headers Map<String,Object> map) throws IOException {
        if (map.get("error") != null) {
            try {
                channel.basicNack((Long) map.get(AmqpHeaders.DELIVERY_TAG), false, true); // 否认消息
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        channel.basicQos(1);
        System.out.println("removeStudent consumer = " + ids);
        String[] split = ids.split(",");
        for (String id:split) {
            int i = Integer.parseInt(id);
            studentMapper.removeStudent(i);
        }

        try {
            //手动ack应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
            //丢弃这条消息
            try {
                //最后一个参数是：是否重回队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
                //拒绝消息
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
                //消息被丢失
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                //消息被重新发送
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
                //多条消息被重新发送
                //channel.basicNack(message.getMessageProperties().getDeliveryTag(), true, true);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    @RabbitListener(bindings ={
            @QueueBinding(
                    value = @Queue(value = "stuUpdate",autoDelete = "false"),
                    key={"update"},
                    exchange = @Exchange(type = "topic",name="stuEx")
            )})
    public void update(Student student , Channel channel,Message message,@Headers Map<String,Object> map) throws IOException {
        if (map.get("error") != null) {
            try {
                channel.basicNack((Long) map.get(AmqpHeaders.DELIVERY_TAG), false, true); // 否认消息
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        channel.basicQos(1);
        System.out.println("updateStudent consumer = " + student);

        int result = studentMapper.updateStudent(student);

        try {
            //手动ack应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
            //丢弃这条消息
            try {
                //最后一个参数是：是否重回队列
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
                //拒绝消息
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
                //消息被丢失
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                //消息被重新发送
                //channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
                //多条消息被重新发送
                //channel.basicNack(message.getMessageProperties().getDeliveryTag(), true, true);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

}